package br.com.musclebook.entity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.Size;

import br.com.musclebook.enums.RoutineIntensity;

@Entity
@NamedQueries({ 
    @NamedQuery(name = "Routine.findById", query = "select rout from Routine rout " +
    		"inner join fetch rout.routineDays as day " +
    		"inner join fetch day.routineDayTrainings as training " +
    		"left join fetch training.exerciseExecutionSets as exercise " +
    		"left join fetch exercise.executionSets " +
    		"where rout.id = :id"), 
    @NamedQuery(name = "Routine.list", query = "select userRoutine from Routine userRoutine where userRoutine.user.id = :userId"),
    @NamedQuery(name = "Routine.updateRate", query = "update Routine set rate = :rate  where id = :routineId")
    })
public class Routine implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @Enumerated(EnumType.ORDINAL)
    private RoutineIntensity intensity;

    @Column(name = "DURATION")
    private Integer durationInWeeks;
    
    private Integer rate;

    @ManyToOne
    @JoinColumn(name = "USER_ID")
    private User user;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "CREATION")
    private Date creation;

    @Size(min = 1, max = 7)
    @OneToMany(mappedBy = "routine", cascade = { CascadeType.ALL }, orphanRemoval = true)
    @OrderBy("dayOfWeek")
    private Set<RoutineDay> routineDays;

    public Routine() {
	this.durationInWeeks = 1;
	this.creation = new Date();
	this.routineDays = new TreeSet<RoutineDay>();
    }

    public Routine(User user) {
	this();
	this.user = user;
    }

    public Long getId() {
	return id;
    }

    public void setId(Long id) {
	this.id = id;
    }

    public String getName() {
	return name;
    }

    public void setName(String name) {
	this.name = name;
    }

    public RoutineIntensity getIntensity() {
	return intensity;
    }

    public void setIntensity(RoutineIntensity intensity) {
	this.intensity = intensity;
    }

    public Integer getDurationInWeeks() {
	return durationInWeeks;
    }
    
    public Integer getRate() {
        return rate;
    }

    public void setRate(Integer rate) {
        this.rate = rate;
    }

    public Date getCreation() {
	return creation;
    }

    public void setCreation(Date creation) {
	this.creation = creation;
    }

    public User getUser() {
	return user;
    }

    public void setUser(User user) {
	this.user = user;
    }

    public void setDurationInWeeks(Integer durationInWeeks) {
	this.durationInWeeks = durationInWeeks;
    }

    public Set<RoutineDay> getRoutineDays() {
	return this.routineDays;
    }
    
    public List<RoutineDay> getRoutineDaysAsList() {
	ArrayList<RoutineDay> arrayList = new ArrayList<RoutineDay>(this.routineDays);
	Collections.sort(arrayList);
	return arrayList;
    }

    public void setRoutineDays(Set<RoutineDay> routineDays) {
	this.routineDays = routineDays;
    }

    public boolean addRoutineDay(RoutineDay routineDay) {
	return this.routineDays.add(routineDay);
    }
    
    public boolean removeRoutineDay(RoutineDay routineDay) {
	return this.routineDays.remove(routineDay);
    }
    
    public boolean isUserCurrentRoutine() {
	boolean current = false;
	if(this.user != null && this.user.getCurrentRoutine() != null && this.user.getCurrentRoutine().getRoutine().getId().equals(this.id)) {
	    current = true;
	}
	
	return current;
    }

}
